# -*- coding: utf-8 -*-
#
# Copyright © 2009-2010 Pierre Raybaut
# Licensed under the terms of the MIT License
# (see spyderlib/__init__.py for details)

#This file is part of pyLot library.
#
# pyLot is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pyLot is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with pyLot.  If not, see <http://www.gnu.org/licenses/>.

__author__ = u'Pierre Puiseux, Guillaume Baty'
__copyright__ = u"Copyright 2011-2012 (C) andheo, Université de Pau et des Pays de l'Adour"
__credits__ = [u'Pierre Puiseux', u'Guillaume Baty']
__license__ = "GNU Lesser General Public License"

__all__ = ['GuiPathManager', 'GuiFileNameManager', 'GuiListManager']

"""Spyder value manager"""


from Qt4.QtGui import (QWidget, QListWidget, QVBoxLayout, QHBoxLayout,
                       QMessageBox, QListWidgetItem, QAbstractItemView)
from Qt4.QtCore import Qt, SIGNAL
from Qt4.compat import getexistingdirectory, getopenfilenames

from Qt4 import QtGui, QtCore

import os, sys
import fnmatch


from pyLot.core import DirPath, FilePath, Datum

from _pylot.qtgui.widgets.gui_typedchoosers import make_chooser
from _pylot.qtgui.widgets.gui_dialog import GuiDialog
from _pylot.qtgui.tools import get_icon

def create_toolbutton(parent, text=None, shortcut=None, icon=None, tip=None,
                      toggled=None, triggered=None,
                      autoraise=True, text_beside_icon=False):
    """Create a QToolButton"""
    button = QtGui.QToolButton(parent)
    if text is not None:
        button.setText(text)
    if icon is not None:
        if isinstance(icon, (str, unicode)):
            icon = get_icon(icon)
        button.setIcon(icon)
    if text is not None or tip is not None:
        button.setToolTip(text if tip is None else tip)
    if text_beside_icon:
        button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
    button.setAutoRaise(autoraise)
    if triggered is not None:
        QtCore.QObject.connect(button, SIGNAL('clicked()'), triggered)
    if toggled is not None:
        QtCore.QObject.connect(button, SIGNAL("toggled(bool)"), toggled)
        button.setCheckable(True)
    if shortcut is not None:
        button.setShortcut(shortcut)
    return button

class GuiListManager(QWidget):
  def __init__(self, value_list=[], ro_value_list=[],
         nature=unicode, filters=u'', title=None, toolbars=True):
    QWidget.__init__(self)

    # Destroying the C++ object right after closing the dialog box,
    # otherwise it may be garbage-collected in another QThread
    # (e.g. the editor's analysis thread in Spyder), thus leading to
    # a segmentation fault on UNIX or an application crash on Windows
    self.setAttribute(Qt.WA_DeleteOnClose)

    if not issubclass(nature, unicode):
      raise NotImplementedError

    self.nature = nature

    self.filters = filters
    if title :
      self.caption = title
    else:
      self.caption = tr_(u"Select file")

    assert isinstance(value_list, list)
    self.value_list = value_list
    if ro_value_list is None:
      ro_value_list = []
    self.ro_value_list = ro_value_list

    self.setWindowTitle(tr_(u"list manager"))
    self.setWindowIcon(get_icon(u'pythonvalue.png'))
    self.resize(500, 300)

    self.selection_widgets = []

    layout = QVBoxLayout()
    self.setLayout(layout)

    if toolbars :
      self.top_layout = QHBoxLayout()
      layout.addLayout(self.top_layout)
      self.toolbar_widgets1 = self.setup_top_toolbar(self.top_layout)

    self.listwidget = QListWidget(self)
    self.listwidget.setSelectionMode(QAbstractItemView.MultiSelection)
    self.connect(self.listwidget, SIGNAL("currentRowChanged(int)"),
           self.refresh)
    layout.addWidget(self.listwidget)

    if toolbars :
      self.bottom_layout = QHBoxLayout()
      layout.addLayout(self.bottom_layout)
      self.toolbar_widgets2 = self.setup_bottom_toolbar(self.bottom_layout)

    self.update_list()
    self.refresh()

  def _add_widgets_to_layout(self, layout, widgets):
    layout.setAlignment(Qt.AlignLeft)
    for widget in widgets:
      layout.addWidget(widget)

  def getValue(self):
    return self.value_list[self.listwidget.currentRow()]

  def setup_top_toolbar(self, layout):
    toolbar = []
    movetop_button = create_toolbutton(self,
                  text=tr_(u"Top"),
                  icon=get_icon(u'spyder_2uparrow.png'),
                  triggered=lambda: self.move_to(absolute=0),
                  text_beside_icon=True)
    toolbar.append(movetop_button)
    moveup_button = create_toolbutton(self,
                  text=tr_(u"Up"),
                  icon=get_icon(u'spyder_1uparrow.png'),
                  triggered=lambda: self.move_to(relative= -1),
                  text_beside_icon=True)
    toolbar.append(moveup_button)
    movedown_button = create_toolbutton(self,
                  text=tr_(u"Down"),
                  icon=get_icon(u'spyder_1downarrow.png'),
                  triggered=lambda: self.move_to(relative=1),
                  text_beside_icon=True)
    toolbar.append(movedown_button)
    movebottom_button = create_toolbutton(self,
                  text=tr_(u"Bottom"),
                  icon=get_icon(u'spyder_2downarrow.png'),
                  triggered=lambda: self.move_to(absolute=1),
                  text_beside_icon=True)
    toolbar.append(movebottom_button)
    self.selection_widgets.extend(toolbar)
    self._add_widgets_to_layout(layout, toolbar)
    return toolbar

  def setup_bottom_toolbar(self, layout):
    toolbar = []
    self.add_button = create_toolbutton(self, text=tr_(u"Add value"),
                     icon=get_icon(u'add.png'),
                     triggered=self.actionAddValue,
                     text_beside_icon=True)
    toolbar.append(self.add_button)
    self.remove_button = create_toolbutton(self, text=tr_(u"Remove value"),
                      icon=get_icon(u'remove.png'),
                      triggered=self.remove_value,
                      text_beside_icon=True)
    toolbar.append(self.remove_button)
    self.selection_widgets.append(self.remove_button)
    self._add_widgets_to_layout(layout, toolbar)
    layout.addStretch(1)
    return toolbar

  def get_value_list(self):
    """Return value list (does not include the read-only value list)"""
    return self.value_list

  def update_list(self):
    """Update value list"""
    if self.nature is DirPath :
      icon = get_icon(u'optionsOpen.png')
    else :
      icon = get_icon(u'compfile.png')
    self.listwidget.clear()
    for name in self.value_list + self.ro_value_list:
      item = QListWidgetItem(name)
      item.setIcon(icon)
      if name in self.ro_value_list:
        item.setFlags(Qt.NoItemFlags)
      self.listwidget.addItem(item)
    self.refresh()

  def refresh(self, row=None):
    """Refresh widget"""
    for widget in self.selection_widgets:
      widget.setEnabled(self.listwidget.currentItem() is not None)
    not_empty = self.listwidget.count() > 0

  def move_to(self, absolute=None, relative=None):
    index = self.listwidget.currentRow()
    if absolute is not None:
      if absolute:
        new_index = len(self.value_list) - 1
      else:
        new_index = 0
    else:
      new_index = index + relative
    new_index = max(0, min(len(self.value_list) - 1, new_index))
    value = self.value_list.pop(index)
    self.value_list.insert(new_index, value)
    self.update_list()
    self.listwidget.setCurrentRow(new_index)

  def remove_value(self):
    answer = QMessageBox.warning(self, tr_(u"Remove items"),
      tr_(u"Do you really want to remove selected items ?"),
      QMessageBox.Yes | QMessageBox.No)
    if answer == QMessageBox.Yes:
      remove_list = []
      for index in self.listwidget.selectedIndexes() :
        remove_list.append(self.value_list[index.row()])

    for value in remove_list :
      self.value_list.remove(value)
    self.update_list()

  def actionAddValue(self):
    datum = Datum(u'd', self.nature, alias=self.caption)
    chooser = make_chooser(datum)
    dialog = GuiDialog(chooser)
    res = dialog.exec_()
    if res :
      self.addValues([chooser.value()])

  def addValues(self, values):
    for value in values :
      value = self.nature(unicode(value))
      self.last_value = value
      if value in self.value_list:
        answer = QMessageBox.question(self, tr_(u"Add value"),
          tr_(u"Value %s is already in list."
            "Do you want to move it to the top of the list ?") % value,
          QMessageBox.Yes | QMessageBox.No)
        if answer == QMessageBox.Yes:
          self.value_list.remove(value)
          self.value_list.insert(0, value)
        else:
          return
      else :
        self.value_list.append(value)
    self.update_list()

class GuiPathManager(GuiListManager):

  def __init__(self, value_list=[], ro_value_list=[], nature=DirPath,
               filters=u'', title=None):
    GuiListManager.__init__(self, value_list=value_list, ro_value_list=ro_value_list,
                            nature=nature, filters=filters, title=title)
    self.last_value = os.getcwdu()


  def actionAddValue(self):
    values = []
    if self.nature is DirPath :
      value = getexistingdirectory(self, tr_(u"Select directory"), self.last_value)
      if value :
        values = [value]
    else :
      values, filters = getopenfilenames(self, self.caption, self.last_value,
                                        filters=self.filters)
    self.addValues(values)

  def addValues(self, values):
    for value in values :
      value = self.nature(unicode(value)).absvalue()
      self.last_value = value
      if value in self.value_list:
        answer = QMessageBox.question(self, tr_(u"Add value"),
          tr_(u"Path %s is already in list."
            "Do you want to move it to the top of the list ?") % value,
          QMessageBox.Yes | QMessageBox.No)
        if answer == QMessageBox.Yes:
          self.value_list.remove(value)
          self.value_list.insert(0, value)
        else:
          return
      else :
        self.value_list.append(value)
    self.update_list()

  def getValues(self):
    return self.get_value_list()

  def getSelectedPaths(self):
#    values = []
#    for index in self.listwidget.selectedIndexes():
#      values.append(self.value_list[index.row()])
#    return values

    values = []
    paths = [self.value_list[idx.row()] for idx in self.listwidget.selectedIndexes()]
    for path in self.value_list :
      if path in paths:
        values.append(path)
    return values


class GuiFileNameManager(GuiPathManager):
  def __init__(self, value_list=[], ro_value_list=[], filters=u'', title=None):
    GuiPathManager.__init__(self, value_list=value_list, ro_value_list=ro_value_list,
                            nature=FilePath, filters=filters, title=title)

  def addValues(self, values):
    for value in values :
      value = self.nature(unicode(value)).name
      self.last_value = value
      if value in self.value_list:
        answer = QMessageBox.question(self, tr_(u"Add value"),
          tr_(u"Path %s is already in list."
            " Do you want to move it to the top of the list ?") % value,
          QMessageBox.Yes | QMessageBox.No)
        if answer == QMessageBox.Yes:
          self.value_list.remove(value)
          self.value_list.insert(0, value)
        else:
          return
      else :
        self.value_list.append(value)
    self.update_list()

class GuiListSelector(GuiListManager):
  def __init__(self, value_list=[], title=None):
    GuiListManager.__init__(self, value_list=value_list, toolbars=False)

    self.listwidget.setSelectionMode(QAbstractItemView.SingleSelection)

    self.lineedit = QtGui.QLineEdit(u'*')
    self.lineedit.textChanged[unicode].connect(self.textChanged)

    self.completer = QtGui.QCompleter(value_list)
    self.completer.setCaseSensitivity(QtCore.Qt.CaseInsensitive)
    self.completer.setCompletionMode(QtGui.QCompleter.InlineCompletion)
    self.lineedit.setCompleter(self.completer)

    self.layout().insertWidget(0, self.lineedit)
    self.layout().insertWidget(0, QtGui.QLabel(u'Filtre :'))

    self.resize(QtCore.QSize(300, 450))

  def textChanged(self, text):
    nvisible = 0
    lastvisible = None
    text = unicode(text)
    for idx in range(self.listwidget.count()):
      if fnmatch.fnmatch(self.value_list[idx], text):
        self.listwidget.setRowHidden(idx, False)
        lastvisible = idx
        nvisible += 1
      else :
        self.listwidget.setRowHidden(idx, True)

    if nvisible == 1 :
      item = self.listwidget.item(lastvisible)
      item.setSelected(True)

if __name__ == "__main__":
  """Run value manager test"""
  from Qt4 import QtGui
  app = QtGui.QApplication(sys.argv)

  test = GuiListSelector([u'a', u'b', u'c'])
  test.show()

#  test = GuiPathManager(sys.path[:3], sys.path[-3:])
#  test2 = GuiPathManager(sys.path[:3], sys.path[-3:], nature=FilePath)
#  test3 = GuiFileNameManager()
#  test.show()
#  test2.show()
#  test3.show()
#  print test.get_value_list()
#  print test.getValue()
  end = app.exec_()
  sys.exit(end)

